#include "ct_config.h"
#include "ct_uartV2.h"

// Global UART configuration structures
UART_t g_Uart0;
#ifdef CT_USE_UART1
UART_t g_Uart1;
#endif

/* UART0 interrupt vector demo */
#if defined   __C51__
void          Serial_ISR(void) interrupt 4
#elif defined __ICC8051__
#pragma vector = 0x23
__interrupt void SerialPort0_ISR(void)
#elif defined __SDCC__
void Serial_ISR(void) __interrupt(4)
#endif /* __SDCC__ */
{
    uint8_t SFRS_TMP;
    SFRS_TMP = SFRS; /* for SFRS page */
    if (RI) {
        RI = 0;    // Clear receive interrupt flag
        ct_uart_IntReceiveBuff(&g_Uart0);
    }
    if (TI) {
        TI = 0;    // Clear transmit interrupt flag
        // Transmit next byte from the buffer, if available
        ct_uart_Transmission(&g_Uart0);
    }
    if (SFRS_TMP) /* for SFRS page */
    {
        ENABLE_SFR_PAGE1;
    }
}

#ifdef CT_USE_UART1
/* UART1 interrupt vector demo */
#if defined   __C51__
void          SerialPort1_ISR(void) interrupt 15
#elif defined __ICC8051__
#pragma vector = 0x7B
__interrupt void SerialPort1_ISR(void)
#elif defined __SDCC__
void SerialPort1_ISR(void) __interrupt(15)
#endif
{
    SFRS_TMP = SFRS; /* for SFRS page */
    if (RI_1) {
        RI_1 = 0; /* clear reception flag for next reception */
        // ct_uart_IntRead(&g_Uart1);
    }
    if (TI_1) {
        TI_1 = 0; /* clear transmission flag for next transmission */
        // g_Uart0.tx_bBusy = 0;    // Clear transmit busy status
    }

    if (SFRS_TMP) /* for SFRS page */
    {
        ENABLE_SFR_PAGE1;
    }
}
#endif /* CT_USE_UART1 */

/**
 * @brief Open the UART interface with specified baud rate.
 *
 * This function initializes the UART interface with a given system clock and baud rate. It configures the UART port for communication.
 *
 * @param u32SysClock The system clock frequency in Hz.
 * @param Port The UART port to be used.
 * @param u32Baudrate The desired baud rate for UART communication.
 */
void ct_uart_Open(uint32_t       u32SysClock,
                  ct_uart_port_t Port,
                  uint32_t       u32Baudrate) {
    UART_Open(u32SysClock, Port, u32Baudrate);
}

// Initialize the UART interface
void ct_uart_Init(UART_t        *UARTx,
                  ct_uart_port_t id,
                  uint32_t       baudrate,
                  int8_t        *rx_buffer_space,
                  uint16_t        rx_buffer_size,
                  int8_t        *tx_buffer_space,
                  uint16_t        tx_buffer_size) {
    if (UARTx == NULL) {
        return;
    }

    // Initialize UART hardware, baud rate, etc.

    if (id == CT_UART0) {
        UARTx->id = CT_UART0;
        // Configuration for UART0
        P06_QUASI_MODE;
        P07_INPUT_MODE;
        ct_uart_Open(24000000, CT_UART0_TIMER1, baudrate);
        ENABLE_UART0_PRINTF;
        ENABLE_UART0_INTERRUPT; /* Enable UART0 interrupt */
    }
#ifdef CT_USE_UART1
    else if (id == CT_UART1) {
        UARTx->id = CT_UART1;
        // Configuration for UART1
        P16_QUASI_MODE;
        P02_INPUT_MODE;
        ct_uart_Open(24000000, CT_UART1_TIMER3, baudrate);
        ENABLE_UART1_PRINTF;
        // ENABLE_UART1_INTERRUPT; // Uncomment to enable UART1 interrupt, ISR is in uart.c file
    }
//  ENABLE_GLOBAL_INTERRUPT; /* Global interrupt enable */
#endif
    // Initialize the ring buffer for reception
    ringbuf_init(&UARTx->rx_ringbuffer, rx_buffer_space, rx_buffer_size);
    ringbuf_init(&UARTx->tx_ringbuffer, tx_buffer_space, tx_buffer_size);
}

/**
 * @brief Receive a byte of dat from UART.
 *
 * @param UARTx Pointer to a UART_t structure that contains the configuration information for the UART.
 * @return The received byte of dat.
 */
uint8_t ct_uart_ReceiveData(UART_t *UARTx) {
    uint8_t dat = 0;
    if (UARTx == NULL) {
        return 0;
    }
    if (UARTx->id == CT_UART0) {
        // Configuration for UART0
        // while (!RI)
        ;
        dat = SBUF;
        RI  = 0;
    }
#ifdef CT_USE_UART1
    else if (UARTx->id == CT_UART1) {
        // Configuration for UART1
        // while (!RI_1)
        ;
        dat  = SBUF_1;
        RI_1 = 0;
    }
#endif
    return dat;
}

int8_t ringbuf_put2(RingBuffer_t *rb, int8_t byte) {
    if (ringbuf_full(rb)) {
        return 0;
    }
    CC_ACCESS_NOW(int8_t, rb->buffer[rb->put_ptr]) = byte;
    CC_ACCESS_NOW(int8_t, rb->put_ptr) = (rb->put_ptr + 1) & rb->mask;
    return 1;
}

uint8_t cntset = 2;
// Receive dat from UART in an interrupt context
void ct_uart_IntReceiveBuff(UART_t *UARTx) {
    int8_t Data,vail;

    if (!UARTx) return;
   // Data = ct_uart_ReceiveData(UARTx);
    if (UARTx->id == CT_UART0) {
        Data = SBUF;

    }
    UARTx->rx_timeout = 0;
    
    vail = ringbuf_put2(&UARTx->rx_ringbuffer, Data);
    // Use the ringbuffer to store the received dat
    if (vail == 0) {
      
        // Handle overflow
       UARTx->rx_bOverflow = 1; 
    }
}

// Send a byte of dat via UART
void ct_uart_SendData(UART_t *UARTx, uint8_t dat) {
    if (!UARTx) return;
    // Wait for previous transmission to complete
    while (UARTx->tx_bBusy)
        ;
    if (UARTx->id == CT_UART0) {
        TI   = 0;
        SBUF = dat;
        while (TI == 0)
            ;
        TI = 0;
    }
#ifdef CT_USE_UART1
    else if (UARTx->id == CT_UART1) {
        TI_1   = 0;
        SBUF_1 = dat;
        while (TI_1 == 0)
            ;
        TI_1 = 0;
    }
#endif
    // Send the dat
    UARTx->tx_bBusy = 1;
}

// Send a buffer of dat via UART
void ct_uart_SendBuff(UART_t *UARTx, int8_t *buff, uint8_t len) {
    uint8_t i;
    for (i = 0; i < len; ++i) {
        ct_uart_SendData(UARTx, buff[i]);
    }
}

/**
 * @brief Put a buffer of data into the UART transmit ringbuffer.
 *
 * @param UARTx Pointer to a UART_t structure that contains the configuration information for the UART.
 * @param buff Pointer to the buffer of data to send.
 * @param len Length of the buffer to send.
 * @return int 0 if all data is put into the ringbuffer successfully, -1 if the ringbuffer is full.
 */
int8_t ct_uart_PutBuff(UART_t *UARTx, int8_t *buff, uint8_t len) {
    uint8_t i;
    if (UARTx == NULL || buff == NULL) {
        return -1;
    }

    for (i = 0; i < len; ++i) {
        // Attempt to put data into the transmit ringbuffer
        if (!ringbuf_put(&UARTx->tx_ringbuffer, buff[i])) {
            // Ringbuffer is full, return an error
            return -1;
        }
    }
    return 0;    // All data was put into the ringbuffer successfully
}
int8_t ringbuf_elements2(const RingBuffer_t *rb) {
    return (rb->put_ptr - rb->get_ptr) & rb->mask;
}

char ringbuf_get2(RingBuffer_t *rb, int8_t *byte) {
    if (ringbuf_empty(rb)) {
        return -1;
    }
    *byte = CC_ACCESS_NOW(int8_t, rb->buffer[rb->get_ptr]);
    CC_ACCESS_NOW(int8_t, rb->get_ptr) = (rb->get_ptr + 1) & rb->mask;
    return 1;
}

/**
 * @brief Start or continue UART transmission from the transmit ringbuffer.
 *
 * @param UARTx Pointer to a UART_t structure that contains the configuration information for the UART.
 */
void ct_uart_Transmission(UART_t *UARTx) {
    uint8_t dat;
    if ((UARTx == NULL)) {
        return;
    }
    if (ringbuf_elements2(&UARTx->tx_ringbuffer) > 0) {
        if (ringbuf_get2(&UARTx->tx_ringbuffer, &dat)) {
            SBUF = dat;    // Start transmission
        }
    } else {
        g_Uart0.tx_bBusy = 0;    // No more dat to send
    }
}

void ct_uart_IntTransmission(UART_t *UARTx) {
    if (!UARTx) return;

    if (UARTx->id == CT_UART0) {
        TI = 1;
    }
#ifdef CT_USE_UART1
    else if (UARTx->id == CT_UART1) {
        TI_1 = 1;
    }
#endif
}

// Reset the interrupt send flag
void ct_uart_ResetIntSendFlag(UART_t *UARTx) {
    UARTx->tx_bBusy = 0;
}

// Send a string of dat via UART
void ct_uart_SendString(UART_t *UARTx, uint8_t *str) {
    while (*str != '\0') {
        ct_uart_SendData(UARTx, *str++);
    }
}

/**
 * @brief Enable or disable UART interrupt.
 *
 * This function enables or disables the UART interrupt based on the status parameter provided.
 *
 * @param id The identifier for the UART port.
 * @param Status The interrupt status (ENABLE or DISABLE).
 */
void ct_uart_InterruptEnable(ct_uart_port_t id, uint8_t Status) {
    switch (id) {
        case UART0:
            switch (Status) {
                case Disable:
                    DISABLE_UART0_INTERRUPT;
                    break;
                case Enable:
                    ENABLE_UART0_INTERRUPT;
                    break;
            }
            break;
#ifdef CT_USE_UART1
        case UART1:
            switch (Status) {
                case Disable:
                    DISABLE_UART1_INTERRUPT;
                    break;
                case Enable:
                    ENABLE_UART1_INTERRUPT;
                    break;
            }
            break;
#endif
        default:
            break;
    }
}

/**
 * @brief Control the interrupt status of UART ports other than the one specified.
 *
 * This function enables or disables interrupts for UART ports other than the one
 * referenced by the UARTx parameter. It is typically used to prevent interrupt
 * conflicts when multiple UART ports are used.
 *
 * @param UARTx Pointer to a UART_t structure that contains the configuration information for the specified UART.
 * @param enable A flag to specify whether to enable (non-zero value) or disable (zero value) the interrupts.
 */
void ControlUARTInterrupts(UART_t *UARTx, unsigned char enable) {
    if (UARTx == NULL) {
        return;    // If the passed pointer is NULL, return directly
    }

    // Disable or enable interrupts for other UART ports based on the id of the passed UART_t instance
    switch (UARTx->id) {
        case CT_UART0:
            // If it's UART0, disable or enable interrupts for UART1 based on the value of enable
            ct_uart_InterruptEnable(CT_UART1, enable);
            break;
#ifdef CT_USE_UART1
        case CT_UART1:
            // If it's UART1, disable or enable interrupts for UART0 based on the value of enable
            ct_uart_InterruptEnable(CT_UART0, enable);
            break;
            // If there are more UART ports, you can continue to add case statements
#endif
        default:
            break;
    }
}